package io.elegant.sessions

import android.content.Context
import android.view.ViewGroup
import com.google.protobuf.Any
import io.elegant.*
import io.elegant.ElegantApiGrpc.ElegantApiStub
import io.grpc.stub.StreamObserver
import kotlinx.coroutines.launch
import java.lang.Exception

class ActivitySession(
    stub: ElegantApiStub,
    private val context: Context
): BaseSession(stub, context) {
    private val layout = context
        .toActivity()
        ?.findViewById<ViewGroup>(android.R.id.content)
    override val sendStreamObserver: StreamObserver<Elegant.Interaction> = stub.activity(receiveStreamObserver)
    fun onStart() = sendAction("onStart")
    fun onStop() = sendAction("onStop")
    fun onPause() = sendAction("onPause")
    fun onResume() = sendAction("onResume")
    fun onBackPressed(callback: (Boolean) -> Unit) = csMain.launch {
        val r = sendActionUntilCallbackResult("onBackPressed")
        callback(r.toBoolValue())
    }
    override suspend fun onReceive(name: String, sessionId: Long, futureId: Long, vararg argv: Any) {
        when (name) {
            "getScreenSize" -> getScreenSize(sessionId, futureId)
            "getTitle" -> getTitle(sessionId, futureId)
            "setTitle" -> setTitle(*argv)
            "accessibilityNotice" -> accessibilityNotice(*argv)
            "setTouchExploration" -> setTouchExploration(*argv)
            "getClipboardText" -> getClipboardText(sessionId, futureId)
            "setClipboardText" -> setClipboardText(*argv)
            "isScrollable" -> isScrollable(sessionId, futureId)
            "setScrollable" -> setScrollable(*argv)
            "vibrate" -> vibrate(*argv)
            else -> super.onReceive(name, sessionId, futureId, *argv)
        }
    }
    override fun destroy() {
        onDestroyedListener = null
        super.destroy()
        context.toActivity()?.finish()
    }
    private fun getTitle(sessionId: Long, futureId: Long) {
        val title = context.toActivity()?.title?.toString()
        onGetTitle(title.toAny(), sessionId, futureId)
    }
    private fun onGetTitle(title: Any, sessionId: Long, futureId: Long) = sendAction("onGetTitle", sessionId, futureId, title)
    private fun setTitle(vararg argv: Any) {
        context.toActivity()?.title = argv[0].toStringValueOrNull()
    }
    private fun getClipboardText(sessionId: Long, futureId: Long) {
        val text = context.getClipboardText()
        onGetClipboardText(text.toAny(), sessionId, futureId)
    }
    private fun onGetClipboardText(title: Any, sessionId: Long, futureId: Long) = sendAction("onGetClipboardText", sessionId, futureId, title)
    private fun setClipboardText(vararg argv: Any) {
        context.setClipboardText(argv[0].toStringValueOrNull())
    }
    private fun accessibilityNotice(vararg argv: Any) {
        context.toActivity()?.window?.decorView?.announceForAccessibility(argv[0].toStringValueOrNull())
    }
    private fun getScreenSize(sessionId: Long, futureId: Long) {
        val (width, height) = layout?.let {
            it.width to it.height
        } ?: (0 to 0)
        val d = context.resources.displayMetrics.density
        onGetScreenSize((width / d).toInt().toAny(), (height / d).toInt().toAny(), sessionId, futureId)
    }
    private fun onGetScreenSize(width: Any, height: Any, sessionId: Long, futureId: Long) = sendAction("onGetScreenSize", sessionId, futureId, width, height)
    private fun setTouchExploration(vararg argv: Any) {
        val enable = argv[0].toBoolValue()
        if (enable) {
            context.startTouchExplorationForNirenr()
            context.startTouchExplorationForBoyhood()
            context.startTouchExplorationForTatans()
            return
        }
        context.stopTouchExplorationForNirenr()
        context.stopTouchExplorationForBoyhood()
        context.stopTouchExplorationForTatans()
    }
    private fun findScrollView(): ElegantScrollView? {
        var parent = context
            .toActivity()
            ?.getViewGroup()
        while (parent != null && parent !is ElegantScrollView)
            parent = try {
                parent.parent as ViewGroup
            } catch (e: Exception) {
                e.printStackTrace()
                null
            }
        return parent as ElegantScrollView?
    }
    private fun isScrollable(sessionId: Long, futureId: Long) {
        val isScrollable = findScrollView()?.isScrollable ?: false
        sendAction("onIsScrollable", sessionId, futureId, isScrollable.toAny())
    }
    private fun setScrollable(vararg argv: Any) {
        val isScrollable = argv[0].toBoolValue()
        findScrollView()?.isScrollable = isScrollable
    }
    private fun vibrate(vararg argv: Any) {
        val millis = argv[0].toLongValue()
        val amplitude = argv[1].toIntValue()
        context.vibrate(millis, amplitude)
    }
}